#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>

// 控制台窗口尺寸
#define WIDTH  100  // 增加宽度
#define HEIGHT 40   // 增加高度
#define INIT_LENGTH 5

// 方向键ASCII码
#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77

#define MIN_SPEED 15     // 最快速度(ms)
#define MAX_SPEED 600    // 最慢速度(ms)
int originalSpeed = 400; // 原始速度存储
int speed_c = 0;         // 当前速度修改量

#define MAXscore_c 25   // 分数增加最大值

// 全局变量
int snakeX[200], snakeY[200];  // 蛇身坐标（增加容量）
int length;                    // 当前长度
int direction;                 // 当前方向
int foodX, foodY;              // 食物坐标
int score;                     // 当前得分
int score_c = 1;               // 分数增减值(起始为1)
int highScore;                 // 历史最高分
int speed = 400;               // 移动速度(ms)


void gotoxy(int x, int y);             //定位光标
void setColor(int color);              // 设置控制台颜色
void createMap();                      //创造地图
void explation();                      //规则

void initsnake();                      // 初始化蛇
int isValidPosition(int x, int y);     // 位置有效性检查
int biteself();                        // 身体碰撞检测
int cantcrosswall();                   // 墙壁碰撞检测
void snakemove();                      // 蛇移动逻辑
void keyboardControl();                //键盘控制

void createfood();                     //生成食物

void scoreandtips();                   // 显示得分和提示
void File_out();                       // 读取最高分
void saveScore();                      // 保存最高分
void gameover();                       //游戏结束

void welcometogame();                  //游戏

// 蛇和食物图标定义
#define SNAKE_HEAD "●"  // 蛇头图标
#define SNAKE_BODY "○"  // 蛇身图标
#define FOOD_ICON  "★"  // 食物图标
#define WALL_ICON  "■"  // 墙壁图标

//游戏
void welcometogame()
{
    system("cls");
    
    // 绘制游戏标题
    setColor(10); // 绿色
    gotoxy(40, 2);
    printf("╔════════════════════════════════════════════════╗");
    gotoxy(40, 3);
    printf("║                                                ║");
    gotoxy(40, 4);
    printf("║             贪 吃 蛇 大 冒 险                  ║");
    gotoxy(40, 5);
    printf("║                                                ║");
    gotoxy(40, 6);
    printf("╚════════════════════════════════════════════════╝");
    
    // 绘制蛇形图案
    setColor(11); // 浅蓝色
    gotoxy(45, 8);
    printf("    ██      ██    ");
    gotoxy(45, 9);
    printf("  ██  ██  ██  ██  ");
    gotoxy(45, 10);
    printf("██      ██      ██");
    gotoxy(45, 11);
    printf("██              ██");
    gotoxy(45, 12);
    printf("  ██          ██  ");
    gotoxy(45, 13);
    printf("    ██      ██    ");
    gotoxy(45, 14);
    printf("      ██  ██      ");
    gotoxy(45, 15);
    printf("        ██        ");
    
    // 游戏选项
    setColor(14); // 黄色
    gotoxy(50, 18);
    printf("1. 开始游戏");
    gotoxy(50, 20);
    printf("2. 游戏说明");
    gotoxy(50, 22);
    printf("3. 退出游戏");
    
    // 作者信息
    setColor(13); // 紫色
    gotoxy(45, 30);
    printf("开发者: YourName");
    gotoxy(45, 31);
    printf("版本: 2.0");
    
    setColor(15); // 白色
    gotoxy(45, 35);
    printf("请按数字键选择: ");
    
    char choice = _getch();
    switch (choice) 
    {
    case '1':
        score = 0;
        originalSpeed = 400;  // 恢复初始速度基准值
        speed_c = 0;          // 速度调整量归零
        score_c = 1;          // 分数增加值重置为初始值1
        speed = 400;          // 当前速度重置为初始值
        direction = RIGHT;    // 重置方向（避免残留方向导致蛇异常移动）
        length = INIT_LENGTH; // 强制重置蛇的长度（防止残留长度）
        createMap();
        initsnake();
        createfood();
        File_out();
        scoreandtips();
        snakemove();
        break;
    case '2':
        explation();
        break;
    case '3':
        exit(0);
    default:
        gotoxy(45, 37);
        setColor(12);
        printf("无效输入！请重新选择");
        Sleep(1000);
        welcometogame();
    }
}
//-----------------------------------------

// 设置光标位置
void gotoxy(int x, int y) 
{
    COORD pos = { x, y };
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

// 设置控制台颜色
void setColor(int color) 
{
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}

//-----------------------------------------

// 绘制游戏地图
void createMap() 
{
    system("cls");
    setColor(3); // 青色边框
    
    // 绘制顶部边框
    gotoxy(0, 0);
    for (int j = 0; j < WIDTH; j += 2) 
    {
        printf(WALL_ICON);
    }
    
    // 绘制底部边框
    gotoxy(0, HEIGHT - 1);
    for (int j = 0; j < WIDTH; j += 2) 
    {
        printf(WALL_ICON);
    }
    
    // 绘制两侧边框
    for (int i = 1; i < HEIGHT - 1; i++) 
    {
        gotoxy(0, i);
        printf(WALL_ICON);
        
        gotoxy(WIDTH - 2, i);
        printf(WALL_ICON);
    }
}

// 规则
void explation() 
{
    system("cls");
    setColor(11);
    
    // 标题
    gotoxy(40, 2);
    printf("╔════════════════════════════════════════════════╗");
    gotoxy(40, 3);
    printf("║                游 戏 规 则                     ║");
    gotoxy(40, 4);
    printf("╚════════════════════════════════════════════════╝");
    
    // 规则内容
    setColor(15);
    gotoxy(10, 6);
    printf("1. 使用方向键(↑↓←→)控制蛇的移动");
    
    setColor(14);
    gotoxy(10, 8);
    printf("2. 吃到食物" FOOD_ICON "可以增加蛇的长度和得分");
    
    setColor(12);
    gotoxy(10, 10);
    printf("3. 撞墙或咬到自己游戏结束");
    
    setColor(13);
    gotoxy(10, 12);
    printf("4. 分数增加值初始为1，按F1加速(+2分)，按F2减速(-2分)");
    
    setColor(10);
    gotoxy(10, 14);
    printf("5. 原速度大于320时每吃一个食物，分数增加值+2");
    
    setColor(11);
    gotoxy(10, 16);
    printf("6. 可以刷新最高记录");
    
    setColor(15);
    gotoxy(10, 20);
    printf("按键说明:");
    gotoxy(15, 22);
    printf("F1      - 加速");
    gotoxy(15, 23);
    printf("F2      - 减速");
    gotoxy(15, 24);
    printf("ESC     - 退出游戏");
    gotoxy(15, 25);
    printf("方向键  - 控制移动方向");
    
    setColor(14);
    gotoxy(10, 30);
    printf("按任意键返回主菜单...");
    
    _getch();
    welcometogame();
}

//-----------------------------------------

// 初始化蛇
void initsnake() 
{
    length = INIT_LENGTH;//length=5
    direction = RIGHT;
    // 初始位置
    int startX = 20 + 2 * (rand() % 30);
    int startY = 10 + 2 * (rand() % 15);

    for (int i = 0; i < length; i++) //初始长度为4,
    {
        snakeX[i] = startX + 2 * i;
        snakeY[i] = startY;

        // 校验坐标有效性
        while (!isValidPosition(snakeX[i], snakeY[i])) 
        {
            startX -= 2;
            snakeX[i] = startX + 2 * i;
            if (startX < 2) {
                startX = 2;
                startY++;
            }
        }

        // 防止身体段重叠
        for (int j = 0; j < i; j++) 
        {
            if (snakeX[i] == snakeX[j] && snakeY[i] == snakeY[j]) 
            {
                snakeX[i] += 2;
                if (snakeX[i] >= WIDTH - 2) 
                {
                    snakeX[i] = 2;
                    snakeY[i]++;
                }
                j = -1; // 重新校验所有前段
            }
        }
    }
}

// 位置有效性检查
int isValidPosition(int x, int y) 
{
    return (x > 0 && x < WIDTH - 1 && y > 0 && y < HEIGHT - 1);
}

// 身体碰撞检测
int biteself() 
{
    // 从第4节开始检测（允许初始弯折）
    for (int i = 4; i < length; i++) {
        if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i])
            return 1;
    }
    return 0;
}

// 墙壁碰撞检测
int cantcrosswall() 
{
    return (snakeX[0] <= 0 || snakeX[0] >= WIDTH - 1 ||
        snakeY[0] <= 0 || snakeY[0] >= HEIGHT - 1);
}

// 蛇移动逻辑
void snakemove() 
{
    Sleep(500);
    while (1) 
    {
        keyboardControl();

        // 保存旧头部坐标
        int oldHeadX = snakeX[0];
        int oldHeadY = snakeY[0];

        // 更新头部位置
        switch (direction) 
        {
            case UP:    snakeY[0]--; break;
            case DOWN:  snakeY[0]++; break;
            case LEFT:  snakeX[0] -= 2; break; // 横向移动步长2
            case RIGHT: snakeX[0] += 2; break;
        }

        // 立即碰撞检测
        if (!isValidPosition(snakeX[0], snakeY[0]) || biteself()) 
        {
            gameover();
            return;
        }

        //originalSpeed > 320时分数增减固定
        if (originalSpeed > 320)
        {
            score_c = 1;
            if (GetAsyncKeyState(VK_F1) & 0x8000)
            {
                score_c = 3;
            }
            else if (GetAsyncKeyState(VK_F2) & 0x8000)
            {
                score_c = 1;
            }
        }

        // 吃到食物
        if (snakeX[0] == foodX && snakeY[0] == foodY) 
        {
            length++;
            if (originalSpeed > MIN_SPEED)
            { 
                originalSpeed -= 10;
                speed = originalSpeed;
            }
            if (originalSpeed > 320)
            {
                score += score_c;
                speed = originalSpeed;
            }
            else if (originalSpeed <= 320)
            {
                if (score_c < MAXscore_c) score_c += 2;
                score += score_c;
            }
            createfood();
        }
        else 
        {
            // 擦除旧尾部
            gotoxy(snakeX[length - 1], snakeY[length - 1]);
            printf("  ");
        }

        // 更新身体位置
        for (int i = length - 1; i > 0; i--) 
        {
            snakeX[i] = snakeX[i - 1];
            snakeY[i] = snakeY[i - 1];
        }

        // 绘制蛇身（新位置）
        for (int i = 1; i < length; i++) 
        {
            gotoxy(snakeX[i], snakeY[i]);
            setColor(10); // 绿色蛇身
            printf(SNAKE_BODY);
        }

        // 绘制蛇头
        setColor(14); // 黄色蛇头
        gotoxy(snakeX[0], snakeY[0]);
        printf(SNAKE_HEAD);

        // 边界二次验证
        if (cantcrosswall()) 
        {
            gameover();
            return;
        }

        // 更新显示
        scoreandtips();
        Sleep(speed);

    }
}

//键盘控制
void keyboardControl() {
   // 实时检测功能键状态
    static int lastF1State = 0;
    static int lastF2State = 0;

    // 检测F1状态变化
    if (GetAsyncKeyState(VK_F1) & 0x8000) { // 当前按下
        if (!lastF1State) { // 从松开到按下的状态变化
            originalSpeed = speed; // 保存原速
            speed_c = -10; // 加速10ms
            speed = originalSpeed + speed_c;
            if (speed < MIN_SPEED) speed = MIN_SPEED;
            if (score_c < MAXscore_c) score_c += 2;
        }
        lastF1State = 1;
    }
    else {
        if (lastF1State) { // 从按下到松开的状态变化
            speed = originalSpeed; // 恢复原速
            if (score_c > 3) score_c -= 2;
            speed_c = 0;
        }
        lastF1State = 0;
    }

    // 检测F2状态变化
    if (GetAsyncKeyState(VK_F2) & 0x8000){
        if (!lastF2State) {
            originalSpeed = speed;
            speed_c = 30; // 减速30ms
            speed = originalSpeed + speed_c;
            if (speed > MAX_SPEED) speed = MAX_SPEED;
            if (score_c > 3) score_c -= 2;
        }
        lastF2State = 1;
    }
    else {
        if (lastF2State) {
            speed = originalSpeed;
            if (score_c < MAXscore_c) score_c += 2;
            speed_c = 0;
        }
        lastF2State = 0;
    }

    // 处理方向键和ESC（原有逻辑）
    if (_kbhit()) {
        int key = _getch();
        if (key == 0 || key == 224) {
            key = _getch();
            switch (key) {
            case UP:    if (direction != DOWN) direction = UP; break;
            case DOWN:  if (direction != UP) direction = DOWN; break;
            case LEFT:  if (direction != RIGHT) direction = LEFT; break;
            case RIGHT: if (direction != LEFT) direction = RIGHT; break;
            }
        }
        else if (key == 27) {
            gameover();
        }
    }
}

//-----------------------------------------

// 生成食物
void createfood() 
{
    int valid;
    do {
            valid = 1;
            // 生成偶数X坐标
            foodX = 2 + 2 * (rand() % ((WIDTH - 4) / 2));
            foodY = (rand() % (HEIGHT - 4)) + 2;

            // 检查位置有效性
            if (!isValidPosition(foodX, foodY)) {
                valid = 0;
                continue;
            }

        // 检查是否与蛇身重叠
            for (int i = 0; i < length; i++) {
                if (foodX == snakeX[i] && foodY == snakeY[i]) {
                    valid = 0;
                    break;
                }
            }
         } while (!valid);

    gotoxy(foodX, foodY);
    setColor(12); // 红色食物
    printf(FOOD_ICON);
}

// 显示得分和提示
void scoreandtips() 
{
    // 绘制右侧面板边框
    setColor(6); // 棕色边框
    for (int i = 0; i < HEIGHT; i++) 
    {
        gotoxy(WIDTH, i);
        printf("║");
    }
    
    // 面板标题
    setColor(14); // 黄色标题
    gotoxy(WIDTH + 5, 2);
    printf("游 戏 信 息");
    
    // 分数信息
    setColor(11); // 浅蓝色
    gotoxy(WIDTH + 2, 5);
    printf("当前得分: ");
    setColor(14); // 黄色分数
    printf("%d", score);
    
    setColor(11);
    gotoxy(WIDTH + 2, 7);
    printf("最高得分: ");
    setColor(14);
    printf("%d", highScore);
    
    // 速度信息
    setColor(13); // 紫色
    gotoxy(WIDTH + 2, 10);
    printf("当前速度: ");
    setColor(speed_c < 0 ? 10 : (speed_c > 0 ? 12 : 14)); // 绿色加速, 红色减速, 黄色正常
    printf("%d", (400 - speed) / 10);
    setColor(13);
    printf(" 级");
    
    setColor(11);
    gotoxy(WIDTH + 2, 12);
    printf("分数加成: ");
    setColor(14);
    printf("%d", score_c);
    
    // 操作说明
    setColor(10); // 绿色标题
    gotoxy(WIDTH + 2, 15);
    printf("操 作 说 明");
    
    setColor(15); // 白色内容
    gotoxy(WIDTH + 2, 17);
    printf("方向键: 控制移动");
    gotoxy(WIDTH + 2, 18);
    printf("F1    : 加速 (+2分)");
    gotoxy(WIDTH + 2, 19);
    printf("F2    : 减速 (-2分)");
    gotoxy(WIDTH + 2, 20);
    printf("ESC   : 退出游戏");
    
    // 游戏状态
    setColor(12); // 红色提示
    gotoxy(WIDTH + 2, 25);
    printf("原速度: %d", (400 - originalSpeed) / 10);
    gotoxy(WIDTH + 2, 26);
    if (speed_c < 0) {
        setColor(10);
        printf("加速状态");
    } 
    else if (speed_c > 0) {
        setColor(12);
        printf("减速状态");
    } 
    else {
        setColor(14);
        printf("正常速度");
    }
}

//-----------------------------------------

// 读取最高分
void File_out()
{
    FILE* fp;
    fp = fopen("save.txt", "rb+");
    if (fp == NULL) 
    {
        fp = fopen("save.txt", "w");
        fprintf(fp, "0");
        fclose(fp); 
        highScore = 0;
    }
    else 
    {
        fscanf(fp, "%d", &highScore);
        fclose(fp);
    }
}

// 保存最高分
void saveScore() {
    FILE* fp = fopen("save.txt", "w");
    if (fp) {
        fprintf(fp, "%d", highScore);
        fclose(fp);
    }
}

//-----------------------------------------

// 游戏结束
void gameover() 
{
    system("cls");
    
    // 绘制游戏结束边框
    setColor(12); // 红色边框
    gotoxy(30, 5);
    printf("╔══════════════════════════════╗");
    gotoxy(30, 6);
    printf("║                              ║");
    gotoxy(30, 7);
    printf("║        游 戏 结 束!         ║");
    gotoxy(30, 8);
    printf("║                              ║");
    gotoxy(30, 9);
    printf("╚══════════════════════════════╝");
    
    // 显示得分
    setColor(14); // 黄色
    gotoxy(35, 12);
    printf("最终得分: %d", score);
    
    // 最高分信息
    if (score > highScore) 
    {
        highScore = score;  // 先更新全局变量
        setColor(10); // 绿色
        gotoxy(32, 14);
        printf("★ 创纪录啦! 新最高分! ★");
        saveScore();        // 立即保存
    }
    else 
    {
        setColor(11); // 浅蓝色
        gotoxy(32, 14);
        printf("距离最高分还差: %d", highScore - score);
    }
    
    // 选项菜单
    setColor(15); // 白色
    gotoxy(35, 18);
    printf("1. 重新开始");
    gotoxy(35, 20);
    printf("2. 退出游戏");
    
    setColor(14); // 黄色
    gotoxy(32, 25);
    printf("请选择: ");
    
    char choice = _getch();
    switch (choice) {
    case '1':
        score = 0;
        length = INIT_LENGTH;
        speed = 400;
        welcometogame();
        break;
    case '2':
        exit(0);
    default:
        gameover();
    }
}


int main()
{
    // 设置控制台尺寸
    system("mode con cols=130 lines=45");
    // 设置窗口标题
    system("title 贪吃蛇大冒险 - 豪华版");
    // 初始化随机种子
    srand((unsigned)time(NULL));
    welcometogame();
	return 0;
}